package com.siyu.rehearsal.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.protobuf.ByteString;
import com.itf.calc.proto.ItfModelProto;
import com.itf.calc.proto.ItfServiceGrpc;
import com.siyu.basedata.modelparam.domain.ModelParam;
import com.siyu.basedata.modelparam.service.IModelParamService;
import com.siyu.basedata.plan.domain.Plan;
import com.siyu.basedata.plan.service.IPlanService;
import com.siyu.basedata.pptnrlaste.domain.PptnRLaste;
import com.siyu.basedata.pptnrlaste.service.IPptnRLasteService;
import com.siyu.basedata.pptnrsence.domain.PptnRSence;
import com.siyu.basedata.pptnrsence.service.IPptnRSenceService;
import com.siyu.basedata.rsvrrlaste.domain.RsvrRLaste;
import com.siyu.basedata.rsvrrlaste.service.IRsvrRLasteService;
import com.siyu.basedata.wrprsrbsin.domain.WrpRsrBsin;
import com.siyu.basedata.wrprsrbsin.service.IWrpRsrBsinService;
import com.siyu.basedata.wrprsrhych.domain.WrpRsrHych;
import com.siyu.basedata.wrprsrhych.service.IWrpRsrHychService;
import com.siyu.basedata.xajresult.domain.XajResult;
import com.siyu.basedata.xajresult.service.IXajResultService;
import com.siyu.common.config.grpc.GrpcConfig;
import com.siyu.common.config.minio.MinIOConfigProperties;
import com.siyu.common.constant.MinioOrOssConstants;
import com.siyu.common.constant.RehearsalConstants;
import com.siyu.common.core.domain.AjaxResult;
import com.siyu.common.utils.aliyun.service.FileOssStorageService;
import com.siyu.common.utils.minio.service.FileStorageService;
import com.siyu.common.utils.swmm.SwwmUtil;
import com.siyu.common.utils.uuid.IdUtils;
import com.siyu.model.dispatch.dto.DispatchDto;
import com.siyu.model.dispatch.io.FloodDispatchOutput;
import com.siyu.model.dispatch.io.SingleDamOutput;
import com.siyu.model.dispatch.model.DispatchModel;
import com.siyu.model.xajmodel.XajData;
import com.siyu.model.xajmodel.XajModel;
import com.siyu.predict.utils.DataUtil;
import com.siyu.rehearsal.domain.SwwmResult;
import com.siyu.rehearsal.dto.*;
import com.siyu.rehearsal.grpc.ItfService;
import com.siyu.rehearsal.previewaffectv.domain.PreviewAffectV;
import com.siyu.rehearsal.previewaffectv.service.IPreviewAffectVService;
import com.siyu.rehearsal.previewnd.domain.PreviewNd;
import com.siyu.rehearsal.previewnd.service.IPreviewNdService;
import com.siyu.rehearsal.previewpfbase.domain.PreviewPFbase;
import com.siyu.rehearsal.previewpfbase.service.IPreviewPFbaseService;
import com.siyu.rehearsal.previewpresult.domain.PreviewPResult;
import com.siyu.rehearsal.previewpresult.service.IPreviewPResultService;
import com.siyu.rehearsal.previewresult.domain.PreviewResult;
import com.siyu.rehearsal.previewresult.mapper.PreviewResultMapper;
import com.siyu.rehearsal.previewresult.service.IPreviewResultService;
import com.siyu.rehearsal.previewriska.domain.PreviewRiskA;
import com.siyu.rehearsal.previewriska.service.IPreviewRiskAService;
import com.siyu.rehearsal.previewsresult.domain.PreviewSresult;
import com.siyu.rehearsal.previewsresult.service.IPreviewSresultService;
import com.siyu.rehearsal.service.PlanDispatchService;
import com.siyu.rehearsal.ttdimension.domain.Dimension;
import com.siyu.rehearsal.ttdimension.service.IDimensionService;
import com.siyu.rehearsal.vo.*;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.minio.*;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@Service
public class PlanDispatchServiceImpl implements PlanDispatchService {
    //是否填充PreviewPResult数据
    private static Boolean yanmob = RehearsalConstants.YANMOB;

    private static String zipPath = RehearsalConstants.ZIP_PATH;

    private static String count_type = RehearsalConstants.COUNT_TYPE_CPU_GPU;

    private static Boolean minioOrOss = MinioOrOssConstants.getMinioOrOss();  //控制走,minio或者oss

    @Value("${ip.pengurl}")
    private String pengurl;

    @Value("${ip.hpengurl}")
    private String hpengurl;

    @Autowired
    private IPreviewResultService previewResultService;

    @Autowired
    private IPlanService planService;

    @Autowired
    private IPptnRLasteService pptnRLasteService;

    @Autowired
    private IXajResultService xajResultService;

    @Autowired
    private PreviewResultMapper previewResultMapper;

    @Autowired
    private IModelParamService modelParamService;

    @Autowired
    private IRsvrRLasteService rsvrRLasteService;

    @Autowired
    private IWrpRsrBsinService wrpRsrBsinService;

    @Autowired
    private IWrpRsrHychService wrpRsrHychService;

    @Autowired
    private IPreviewNdService previewNdService;

    @Autowired
    private IPreviewSresultService previewSresultService;

    @Autowired
    private IPreviewPResultService previewPResultService;

    @Autowired
    private IPreviewRiskAService previewRiskAService;

    @Autowired
    private IPreviewAffectVService previewAffectVService;

    @Autowired
    private IDimensionService dimensionService;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;

    @Autowired
    private IPptnRSenceService pptnRSenceService;

    @Autowired
    private FileOssStorageService fileOssStorageService;

    @Autowired
    private IPreviewPFbaseService previewPFbaseService;

    @Autowired
    private GrpcConfig grpcConfig;



    @Override
    public HashMap<String, Object> getRatioData(PlanRatioDto planRatioDto) {

        List<String> ids = planRatioDto.getIds();

        ArrayList<PlanRatioDataVo> planRatioDataVos = new ArrayList<>();
        for (int i = 0; i < ids.size(); i++) {
            String planId = ids.get(i);

            Plan plan = planService.getById(planId);

            // 获取最大in_qt及其时间
            PreviewResult maxInQtResult = previewResultMapper.findMaxInQtAndTime(planId);

            // 获取最大out_qt及其时间
            PreviewResult maxOutQtResult = previewResultMapper.findMaxOutQtAndTime(planId);

            //获取时间序列
            QueryWrapper<PreviewResult> previewResultQueryWrapper = new QueryWrapper<>();
            previewResultQueryWrapper.select("in_qt", "out_qt", "final_level").eq("plan_id", planId);
            List<PreviewResult> list = previewResultService.list(previewResultQueryWrapper);

            Double inv_flood = 0.0;
            Double outv_flood = 0.0;
            for (int j = 0; j < list.size(); j++) {
                if (j == list.size() - 1) {
                    inv_flood = inv_flood;
                    outv_flood = outv_flood;
                } else {
                    // 获取入库流量
                    if (list.get(j).getInQt() != null && list.get(j + 1).getInQt() != null) {
                        inv_flood = inv_flood + (list.get(j).getInQt() + list.get(j + 1).getInQt()) * 1800 / 10000;
                    }
                    // 获取出库流量
                    if (list.get(j).getOutQt() != null && list.get(j + 1).getOutQt() != null) {
                        outv_flood = outv_flood + (list.get(j).getOutQt() + list.get(j + 1).getOutQt()) * 1800 / 10000;
                    }
                }
            }

            planRatioDataVos.add(PlanRatioDataVo.builder()
                    .planName(plan.getPlanName())
                    .maxInQt(maxInQtResult.getInQt())
                    .maxInQtTime(maxInQtResult.getTm())
                    .maxOutQt(maxOutQtResult.getOutQt())
                    .maxOutQtTime(maxOutQtResult.getTm())
                    .totalWarehousing(inv_flood)
                    .totalDelivery(outv_flood)
                    .build());
        }

        // 组装特征指标过程数据
        ArrayList<HashMap<String, List<Double>>> inQt = new ArrayList<>();
        ArrayList<HashMap<String, List<Double>>> outQt = new ArrayList<>();
        ArrayList<HashMap<String, List<Double>>> finalLevel = new ArrayList<>();
        for (int i = 0; i < ids.size(); i++) {

            String planId = ids.get(i);

            Plan plan = planService.getById(planId);


            QueryWrapper<PreviewResult> previewResultQueryWrapper = new QueryWrapper<>();

            previewResultQueryWrapper.select("in_qt", "out_qt", "final_level")
                    .eq("plan_id", planId);
            List<PreviewResult> list = previewResultService.list(previewResultQueryWrapper);

            ArrayList<Double> inQts = new ArrayList<>();
            ArrayList<Double> outQts = new ArrayList<>();
            ArrayList<Double> finalLevels = new ArrayList<>();
            for (int j = 0; j < list.size(); j++) {
                PreviewResult previewResult = list.get(j);
                /*if (previewResult.getInQt()!=null){
                    inQts.add(previewResult.getInQt());
                }
                if (previewResult.getOutQt()!=null){
                    outQts.add(previewResult.getOutQt());
                }
                if (previewResult.getFinalLevel()!=null){
                    finalLevels.add(previewResult.getFinalLevel());
                }*/
                inQts.add(previewResult.getInQt());
                outQts.add(previewResult.getOutQt());
                finalLevels.add(previewResult.getFinalLevel());
            }

            HashMap<String, List<Double>> inQtMap = new HashMap<>();
            HashMap<String, List<Double>> outQtMap = new HashMap<>();
            HashMap<String, List<Double>> finalLevelMap = new HashMap<>();
            inQtMap.put(plan.getPlanName(), inQts);
            outQtMap.put(plan.getPlanName(), outQts);
            finalLevelMap.put(plan.getPlanName(), finalLevels);
            inQt.add(inQtMap);
            outQt.add(outQtMap);
            finalLevel.add(finalLevelMap);

        }
        PreviewResultRatioVo build = PreviewResultRatioVo.builder()
                .inQt(inQt)
                .outQt(outQt)
                .finalLevel(finalLevel)
                .build();
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("planRatioDataVos", planRatioDataVos);
        resultMap.put("planRatioData", build);

        return resultMap;
    }


    @Override
    @Transactional
    public Object getCalculateResult(PlanCalculateDto planCalculateDto) throws Exception {
        // 判断时间间隔
        if (planCalculateDto.getDrORdk()==1){
            List<Date> tms = planCalculateDto.getTms();
            List<Double> fqt = planCalculateDto.getFqt();
            // 获取时间间隔
            Long interval = (tms.get(1).getTime() - tms.get(0).getTime()) / (1000 * 60);
            if (tms.size() <120/interval){
                Date startTime = tms.get(0);
                Date endTime = tms.get(tms.size()-1);
                DateTime targetEndTime = DateUtil.offsetHour(startTime, 2);
                while (endTime.before(targetEndTime)) {
                    endTime = DateUtil.offsetMinute(endTime,interval.intValue());
                    tms.add(endTime);
                    // 补充fqt数据
                    fqt.add(0.0);
                }
                planCalculateDto.setTms(tms);
                planCalculateDto.setFqt(fqt);
            }
        }
        LinkedList<String> ts = new LinkedList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (Date tm : planCalculateDto.getTms()) {
            String format = sdf.format(tm);
            ts.add(format);
        }

        List<Double> areaRains = new ArrayList<>();
        Double totalRainfall = null;
        if (planCalculateDto.getDrORdk() == 0) {
            // 总降雨量
            areaRains = planCalculateDto.getAreaRains();
            totalRainfall = areaRains.stream()
                    .mapToDouble(Double::doubleValue)
                    .sum();
        }

        List<Date> tms = planCalculateDto.getTms();
        Date startTime = tms.get(0);
        Date endTime = tms.get(tms.size() - 1);

        //判断  dispatchType是否传入
        if (planCalculateDto.getDispatchType() == null) {
            planCalculateDto.setDispatchType(RehearsalConstants.DIAO_DU_TYPE_COMMON);
        }

        SingleDamOutput singleDamOutput = null;
        List<Double> fqt = new ArrayList<>();
        if (planCalculateDto.getDrORdk() == 0) {
            //调度模型参数组装
            DispatchDto dispatchDto = DispatchDto.builder()
                    .rscd(planCalculateDto.getRscd())
                    .startTime(startTime)
                    .endTime(endTime)
                    .floodLevel(planCalculateDto.getPlanFtParameter().getFloodLevel())
                    .designWaterLevel(planCalculateDto.getPlanFtParameter().getDesignWaterLevel())
                    .fcQrelease(planCalculateDto.getPlanFtParameter().getFcQrelease())
                    .xzQrelease(planCalculateDto.getPlanFtParameter().getXzQrelease())
                    .qdWaterLevel(planCalculateDto.getPlanFtParameter().getQdWaterLevel())
                    .dispatchType(planCalculateDto.getDispatchType())
                    .areaRains(planCalculateDto.getAreaRains())
                    .tms(planCalculateDto.getTms())
                    .id(planCalculateDto.getId())
                    .planType(planCalculateDto.getPlanType())
                    .build();

            //调度模型计算
            FloodDispatchOutput floodDispatchOutput = DispatchModel.dispatch(dispatchDto);
        /*        if (floodDispatchOutput == null) {
            return "";
        }*/
            List<SingleDamOutput> damList = floodDispatchOutput.getDamList();
            singleDamOutput = damList.get(0);

            fqt = singleDamOutput.getOptimalLine_Qrelease();
        } else {
            fqt = planCalculateDto.getFqt();
        }

        Date before72Hrs = null;
        // 计算三天以前的时间
        before72Hrs = DateUtil.offsetDay(startTime, -3).toJdkDate();
        List<Double> preQ = null;
        if (singleDamOutput != null) {
            HashMap<String, Object> xajResultMap = hisCalc(planCalculateDto);

            // 获取新安江模型计算结果
            preQ = Convert.toList(Double.class, xajResultMap.get("preQ"));
        }
        //List<String> tmss = Convert.toList(String.class, xajResultMap.get("tms"));
        // 修改inp文件时间
        updateXinglongInpTime(before72Hrs, endTime, planCalculateDto.getRscd());

        //向dat文件写入数据
        //接入调度模型的下泄流量
        initHz(before72Hrs, fqt, planCalculateDto.getAreaRains(), ts, planCalculateDto.getRscd());

        // 查询二位水动力计算需求配置文件信息
        QueryWrapper<Dimension> dimensionQueryWrapper = new QueryWrapper<>();
        dimensionQueryWrapper.eq("rscd", planCalculateDto.getRscd())
                .eq("count_type", count_type); //计算类型
        Dimension dimension = dimensionService.getOne(dimensionQueryWrapper);


        //swmm计算 ,读取结果传输溢流过程给二维水动力服务端服务
        Object calculate = SwwmUtil.calculate("siyu-model/src/main/resources/swwm/" + planCalculateDto.getRscd() + ".inp");
        //Object calculate = SwwmUtil.calculate(planCalculateDto.getRscd() + ".inp");
        ArrayList<SwwmResult> swwmResults = savePlan(calculate, ts, planCalculateDto);

        // 组装二位水动力计算需求配置文件信息
        ItfModelProto.ReservoirInfo reservoirInfo = ItfModelProto.ReservoirInfo.newBuilder()
                .setId(dimension.getId())
                .setRscd(dimension.getRscd())
                .setRsname(dimension.getRsname())
                .setCtrlPath(dimension.getCtrlPath())
                .setI17Path(dimension.getI17Path())
                .setFloodPoint(dimension.getFloodPoint())
                .setFilePath(dimension.getFilePath())
                .setOutputPath(dimension.getOutputPath())
                .setHostPath(dimension.getHostPath())
                .build();

        ItfModelProto.WaterDataList.Builder builder = ItfModelProto.WaterDataList.newBuilder();

        for (SwwmResult swwmResult : swwmResults) {
            ItfModelProto.WaterData build = ItfModelProto.WaterData.newBuilder()
                    .setTm(swwmResult.getTm())
                    .setOutletFlow(swwmResult.getOutletFlow())
                    .setWaterLevel(swwmResult.getWaterLevel())
                    .build();
            builder.addData(build);
        }


        ItfModelProto.itfRequest build = ItfModelProto.itfRequest.newBuilder()
                .setSwwmResults(swwmResults.toString())
                .setRscd(planCalculateDto.getRscd())
                .setReservoirInfo(reservoirInfo)
                .setWaterDataList(builder)
                .build();
        //创建连接

        if (swwmResults.size() != 0) {
            if (count_type.equals("cpu")) {
                //ManagedChannel channel = ManagedChannelBuilder.forAddress("hrhy.tpddns.cn", 9090).usePlaintext().build();
                //ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 9092).usePlaintext().build();
                //ManagedChannel channel = ManagedChannelBuilder.forAddress("192.168.0.33", 9092).usePlaintext().build();
                //ManagedChannel channel = ManagedChannelBuilder.forAddress("47.108.227.85", 8601).usePlaintext().build();
                //ManagedChannel channel = ManagedChannelBuilder.forAddress("192.168.11.18", 8601).usePlaintext().build();
                int maxMessagesize = 900 * 1024 * 1024;//设置最大消息大小为100ME
                ManagedChannel channel = ManagedChannelBuilder.forAddress(grpcConfig.getHost(), grpcConfig.getPort()).maxInboundMessageSize(maxMessagesize).usePlaintext().build();
                try {
                    // 使用 channel 进行操作
                    ItfServiceGrpc.ItfServiceBlockingStub itfServiceBlockingStub = ItfServiceGrpc.newBlockingStub(channel);
                    ItfModelProto.itfResponse itfResponse = itfServiceBlockingStub.itfCalc(build);
                    ItfModelProto.FileStreamResponse fileStream = itfResponse.getFileStream();
                    channel.shutdown();

                    // zip文件解压
                    zipChuli(fileStream);
                } finally {
                    if (channel != null) {
                        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
                    }
                }

            } else {
                ItfService itfService = new ItfService();
                itfService.itfCalc(swwmResults, dimension);
            }
        }


        //预演方案保存
        // 风险隐患
        String riskDanger = "";
        if (swwmResults.size() != 0) {
            riskDanger = RehearsalConstants.RISK_DANGER;
        } else {
            riskDanger = RehearsalConstants.NO_RISK_DANGER;
        }
        String sceneType = riskDanger + "+" + planCalculateDto.getPlanType() + RehearsalConstants.RAINFALL;
        //  情景类别
        Plan plan = insertPlan(planCalculateDto, totalRainfall, riskDanger, sceneType);

        //geojson转换json文件上传minio
        //String result = creategejson(tms, plan);

        /*=================================*/
        //String result = uploadedJsonFile(tms, plan,"lingshigeo");


        //可视化结果存储
        PreviewSresult previewSresult = insertPreviewSresult(new ArrayList<String>().toString(), plan, singleDamOutput);

        // 预演计算结果指标组装入库
        PreviewPResult previewPResult = insertPreviewPResult(totalRainfall, tms, singleDamOutput, plan.getId(), riskDanger, planCalculateDto.getPlanFtParameter(), fqt);

        // 风险评估数据入库
        PreviewRiskA previewRiskA = insertPreviewRiskA(plan);

        // 获取预演计算结果指标数据 并入库
        //面雨量
        ArrayList<PreviewResult> previewResults = insertPreviewResult(planCalculateDto, tms, startTime, endTime, singleDamOutput, preQ, plan, fqt);

        //淹没影响村庄
        //ArrayList<PreviewAffectV> previewAffectVS = inserttPreviewAffectV(plan, riskDanger);


        HashMap<String, Object> resultMap = new HashMap<>();

        // 统计数据
        ArrayList<PreviewAffectV> previewAffectVS = depthAndArea(dimension.getRiverArea(), previewRiskA, previewSresult, previewPResult, planCalculateDto.getRscd(), plan);

        resultMap.put("plan", plan);
        resultMap.put("previewSresult", previewSresult);
        resultMap.put("previewPResult", previewPResult);
        resultMap.put("previewRiskA", previewRiskA);
        resultMap.put("previewResults", previewResults);
        if (singleDamOutput != null) {
            // 降雨数据
            ArrayList<PreviewNd> previewNds = insertPreviewNds(areaRains, tms, plan);
            resultMap.put("previewNds", previewNds);
        }
        if (swwmResults.size() != 0 && previewAffectVS.size() != 0) {
            resultMap.put("previewAffectVS", previewAffectVS);
        }

        return resultMap;
    }

    private void zipChuli(ItfModelProto.FileStreamResponse fileStream) {
        //清空./modeldata目录
        Path directoryPath = Paths.get(zipPath);
        try {
            // 获取目录下所有文件
            Files.walk(directoryPath)
                    .filter(path -> !path.equals(directoryPath)) // 确保不会删除目录本身
                    .forEach(path -> {
                        try {
                            // 删除文件
                            Files.delete(path);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });

            System.out.println("./modeldata目录已清理!");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //处理grpc传输文件
        //String fileName = fileStream.getFileName();
        ByteString fileContent = fileStream.getFileContent();
        // 解压缩直接到./modeldata目录
        Path targetDir = Paths.get(zipPath);
        if (!Files.exists(targetDir)) {
            try {
                Files.createDirectories(targetDir);
            } catch (IOException e) {
                System.err.println("Failed to create directory: " + e.getMessage());
            }
        }

        try (ByteArrayInputStream bis = new ByteArrayInputStream(fileContent.toByteArray());
             ZipInputStream zis = new ZipInputStream(bis)) {

            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                if (entry.isDirectory()) {
                    // 创建目录
                    Files.createDirectories(targetDir.resolve(entry.getName()));
                } else {
                    // 写入文件
                    Path newFilePath = targetDir.resolve(entry.getName());
                    try (FileOutputStream fos = new FileOutputStream(newFilePath.toFile())) {
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = zis.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                    }
                }
            }
            System.out.println("文件已解压缩至：" + targetDir);
        } catch (IOException e) {
            System.err.println("解压缩失败: " + e.getMessage());
        }
    }

    /**
     * 渲染数据上传
     *
     * @param tms
     * @param plan
     * @return
     */
    private String uploadedJsonFile(List<Date> tms, Plan plan, String filePath) {
        List<String> uploadedFileUrls = new ArrayList<>();

        try {
            // 指定目录
            Path sourceDir = Paths.get(zipPath);

            // 检查目录是否存在
            if (!Files.exists(sourceDir)) {
                throw new RuntimeException("Source directory does not exist.");
            }


            // 遍历目录中的文件，按时间顺序排序
            // 定义日期时间格式化器
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm");

            // 获取文件列表并按日期时间排序
            List<Path> fileList = Files.walk(sourceDir)
                    .filter(Files::isRegularFile)
                    .sorted(Comparator.comparing(path -> {
                        String fileName = path.getFileName().toString();
                        String datePart = fileName.substring(fileName.indexOf("_") + 1, fileName.lastIndexOf("."));
                        String prefixToRemove = "wDepth_"; // 前缀
                        // 检查文件名是否包含 "max_wDepth"
                        // 如果是 max_wDepth 文件，返回一个特定的日期时间（比如一个将来的时间），
                        // 这样它会在按时间升序排序时排在末尾。
                        if (datePart.contains("max_wDepth")) {
                            return LocalDateTime.MAX;
                        }
                        String cleanDatePart = datePart.startsWith(prefixToRemove) ? datePart.substring(prefixToRemove.length()) : datePart;
                        return LocalDateTime.parse(cleanDatePart, dateTimeFormatter);
                    }))
                    .collect(Collectors.toList());
            Path dirPath = Paths.get(zipPath);
            try {
                Files.list(dirPath).forEach(System.out::println);
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 遍历文件列表，重命名并上传到MinIO
            for (int i = 0; i < fileList.size(); i++) {
                Path file = fileList.get(i);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm");

                if (i <= (tms.size() - 1)) {
                    String formattedTime = sdf.format(tms.get(i));
                    String newFileName = plan.getId() + "_" + formattedTime + ".geojson";
                    Path renamedFile = sourceDir.resolve(newFileName);
                    Files.move(file, renamedFile, StandardCopyOption.REPLACE_EXISTING);
                    try {
                        String accessUrl = "";
                        String path = "";
                        if (minioOrOss) {
                            accessUrl = fileOssStorageService.uploadJsonFile(filePath, newFileName, zipPath + newFileName);
                            path = accessUrl;
                        } else {
                            accessUrl = fileStorageService.uploadJsonFile(filePath, newFileName, zipPath + newFileName);
                            URL url = new URL(accessUrl);
                            path = url.getPath();
                            path = minIOConfigProperties.getReadPath() + path;
                        }
                        uploadedFileUrls.add(path);

                        System.out.println("File uploaded successfully. URL: " + accessUrl);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    try {
                        String newFileName = plan.getId() + "_max_wDepth.geojson";
                        Path renamedFile = sourceDir.resolve(newFileName);
                        Files.move(file, renamedFile, StandardCopyOption.REPLACE_EXISTING);
                        String accessUrl = "";
                        String path = "";
                        if (minioOrOss) {
                            accessUrl = fileOssStorageService.uploadJsonFile(filePath, newFileName, zipPath + newFileName);
                            path = accessUrl;
                        } else {
                            accessUrl = fileStorageService.uploadJsonFile(filePath, newFileName, zipPath + newFileName);
                            URL url = new URL(accessUrl);
                            path = url.getPath();
                            path = minIOConfigProperties.getReadPath() + path;
                        }
                        uploadedFileUrls.add(path);
                        System.out.println("File uploaded successfully. URL: " + accessUrl);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }


            }


            System.out.println("文件已上传至：" + sourceDir);
            System.out.println("上传成功的文件列表：" + uploadedFileUrls);

        } catch (IOException e) {
            System.err.println("上传失败: " + e.getMessage());
        }
        return uploadedFileUrls.toString();
    }

    /**
     * //geojson转换json文件上传minio
     *
     * @param tms
     * @param plan
     * @return
     * @throws ErrorResponseException
     * @throws InsufficientDataException
     * @throws InternalException
     * @throws InvalidBucketNameException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws NoSuchAlgorithmException
     * @throws ServerException
     * @throws XmlParserException
     * @throws RegionConflictException
     */
    private String creategejson(List<Date> tms, Plan plan) throws ErrorResponseException, InsufficientDataException, InternalException, InvalidBucketNameException, InvalidKeyException, InvalidResponseException, NoSuchAlgorithmException, ServerException, XmlParserException, RegionConflictException {
        List<String> uploadedFileUrls = new ArrayList<>();

        try {
            // 指定目录
            Path sourceDir = Paths.get(zipPath);

            // 检查目录是否存在
            if (!Files.exists(sourceDir)) {
                throw new RuntimeException("Source directory does not exist.");
            }


            // 遍历目录中的文件，按时间顺序排序
            // 定义日期时间格式化器
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm");

            // 获取文件列表并按日期时间排序
            List<Path> fileList = Files.walk(sourceDir)
                    .filter(Files::isRegularFile)
                    .sorted(Comparator.comparing(path -> {
                        String fileName = path.getFileName().toString();
                        String datePart = fileName.substring(fileName.indexOf("_") + 1, fileName.lastIndexOf("."));
                        String prefixToRemove = "wDepth_"; // 前缀
                        String cleanDatePart = datePart.startsWith(prefixToRemove) ? datePart.substring(prefixToRemove.length()) : datePart;
                        return LocalDateTime.parse(cleanDatePart, dateTimeFormatter);
                    }))
                    .collect(Collectors.toList());
            Path dirPath = Paths.get(zipPath);
            try {
                Files.list(dirPath).forEach(System.out::println);
            } catch (IOException e) {
                e.printStackTrace();
            }
            //http://hrhy.tpddns.cn/   access key    J2zc7PTm7A31mF5rx3bt
            //http://hrhy.tpddns.cn/   secret key    lF0QCGEjaIT6EOqDSMCHVfsWQKIpx2BOnSBXa58m
            // 使用MinIO客户端
            // access key   VCVWxVkcpwUU18PbAOtE
            // secret key   NeBTp6x8XPr9xCuvJqNB4PdysxJx6euGYCvlawnZ
            MinioClient minioClient = MinioClient.builder()
                    .endpoint("http://192.168.20.233:9000")
                    .credentials("VCVWxVkcpwUU18PbAOtE", "NeBTp6x8XPr9xCuvJqNB4PdysxJx6euGYCvlawnZ")
                    //.credentials("minio", "minio123")
                    .build();
            // 上传文件前确保存储桶存在
            boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket("siyu").build());
            if (!found) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket("siyu").build());
            }


            // 遍历文件列表，重命名并上传到MinIO
            for (int i = 0; i < fileList.size(); i++) {
                Path file = fileList.get(i);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm");
                String formattedTime = sdf.format(tms.get(i));

                String newFileName = plan.getId() + "_" + formattedTime + ".geojson";
                Path renamedFile = sourceDir.resolve(newFileName);
                Files.move(file, renamedFile, StandardCopyOption.REPLACE_EXISTING);
                try {
                    minioClient.uploadObject(
                            UploadObjectArgs.builder()
                                    .bucket("siyu")
                                    .object("geo/" + newFileName)
                                    .filename(zipPath + newFileName)
                                    .build());
                    // 构建文件的访问URL
                    String accessUrl = "http://192.168.20.233:9000/siyu/geo/" + newFileName;
                    uploadedFileUrls.add(accessUrl);

                    System.out.println("File uploaded successfully. URL: " + accessUrl);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }


            System.out.println("文件已上传至：" + sourceDir);
            System.out.println("上传成功的文件列表：" + uploadedFileUrls);

        } catch (IOException e) {
            System.err.println("上传失败: " + e.getMessage());
        }

        String result = uploadedFileUrls.toString();

        //清空./modeldata目录
        Path directoryPath = Paths.get(zipPath);
        try {
            // 获取目录下所有文件
            Files.walk(directoryPath)
                    .filter(path -> !path.equals(directoryPath)) // 确保不会删除目录本身
                    .forEach(path -> {
                        try {
                            // 删除文件
                            Files.delete(path);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });

            System.out.println("All files in the directory have been deleted.");
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * // 降雨数据
     *
     * @param areaRains
     * @param tms
     * @param plan
     * @return
     */
    private ArrayList<PreviewNd> insertPreviewNds(List<Double> areaRains, List<Date> tms, Plan plan) {
        ArrayList<PreviewNd> previewNds = new ArrayList<>();
        for (int i = 0; i < tms.size(); i++) {
            PreviewNd previewNd = new PreviewNd();
            previewNd.setId(IdUtils.getId());
            previewNd.setPlanId(plan.getId());
            previewNd.setDrp(areaRains.get(i));
            previewNd.setTm(tms.get(i));
            previewNds.add(previewNd);
        }
        return previewNds;
    }

    /**
     * 溢流及风险情况
     *
     * @param plan
     * @param maxLevelExceedStandard
     * @return
     */
    private ArrayList<PreviewAffectV> inserttPreviewAffectV(Plan plan, String maxLevelExceedStandard) {
        ArrayList<PreviewAffectV> previewAffectVS = new ArrayList<>();
        String[] strings = new String[]{"凤凰山村", "长源村", "中午村", "西源村"};
        if (maxLevelExceedStandard.equals("存在隐患")) {
            Random random = new Random();
            int i = random.nextInt(10);
            for (int j = 0; j < i; j++) {
                String villageName = strings[random.nextInt(3)];
                PreviewAffectV previewAffectV = PreviewAffectV.builder()
                        .id(IdUtils.getId())
                        .planId(plan.getId())
                        .villageName(villageName)
                        .district("湖南省岳阳市平江县")
                        .lOfficial(villageName + "村长")
                        .inp(random.nextInt(17) + 1)
                        .build();
                previewAffectVS.add(previewAffectV);
            }

        }
        return previewAffectVS;
    }

    /**
     * 预案方案保存
     *
     * @param planCalculateDto
     * @param totalRainfall
     * @param riskDanger
     * @param sceneType
     * @return
     */
    private Plan insertPlan(PlanCalculateDto planCalculateDto, Double totalRainfall, String riskDanger, String sceneType) {
        DecimalFormat df = new DecimalFormat("#.0");
        Plan plan = new Plan();
        plan.setId(IdUtils.getId());  // id
        plan.setPlanType(planCalculateDto.getPlanType());
        plan.setStartTime(planCalculateDto.getTms().get(0));
        plan.setEndTime(planCalculateDto.getTms().get(planCalculateDto.getTms().size() - 1));
        plan.setPlanName("");
        plan.setPlanDesc("");
        plan.setCreateBy("");
        plan.setPreType("预演");      //预报类型
        plan.setPlanType(planCalculateDto.getPlanType());   //方案类型
        if (totalRainfall != null) {
            plan.setTotalRainfall(Double.valueOf(df.format(totalRainfall)));    //总降雨
        }
        plan.setRiskDanger(riskDanger);   //风险隐患
        plan.setSceneType(sceneType);    //情景类别
        plan.setRscd(planCalculateDto.getRscd());   //水库编码
        //方案入库存储
        //planService.insertPlan(plan);
        return plan;
    }

    /**
     * 可视化结果存储
     *
     * @param result
     * @param plan
     */
    private PreviewSresult insertPreviewSresult(String result, Plan plan, SingleDamOutput singleDamOutput) {
        DecimalFormat df = new DecimalFormat("#.00");


        PreviewSresult previewSResult = PreviewSresult.builder()
                .id(IdUtils.getId())
                .planId(plan.getId())
                .geojson(result)   //geojson数据
                .maxFa(10.0)     //最大淹没面积
                .rsvr(1)    //水库数量
                .fv(5)   //淹没村庄数量
                .iPopulace(9.0)    //影响人口
                .aal(6.0)   //影响耕地
                .ah(90)    //影响房屋
                .build();
        if (singleDamOutput != null) {
            // 拦蓄洪量
            double floodRetention = singleDamOutput.getFloodRetention();
            previewSResult.setFStorage(Double.valueOf(df.format(floodRetention * 10000)));   //拦蓄洪量
        }
        //previewSresultService.insertPreviewSresult(previewSResult);
        return previewSResult;
    }

    /**
     * 获取预演计算结果指标数据 并入库
     *
     * @param planCalculateDto
     * @param tms
     * @param startTime
     * @param endTime
     * @param singleDamOutput
     * @param preQ
     * @param plan
     * @throws Exception
     */
    private ArrayList<PreviewResult> insertPreviewResult(PlanCalculateDto planCalculateDto, List<Date> tms, Date startTime, Date endTime, SingleDamOutput singleDamOutput, List<Double> preQ, Plan plan, List<Double> fqt) throws Exception {
        ArrayList<PreviewResult> previewResults = new ArrayList<>();

        DecimalFormat df = new DecimalFormat("#.000");  //流量保留小数位数
        DecimalFormat df1 = new DecimalFormat("#.00");   //水位保留小数位数
        DecimalFormat df2 = new DecimalFormat("#.0");   //雨量保留小数位数
        if (singleDamOutput != null) {
            HashMap<Object, Object> areaRainfall = DataUtil.getAreaRainfall(planCalculateDto.getRscd(), startTime, endTime, 1);
            List<Double> yureareaRains = Convert.toList(Double.class, areaRainfall.get("areaRain"));

            if (planCalculateDto.getPlanType().equals(RehearsalConstants.COUNT_TYPE_SCENE)) {
                yureareaRains = planCalculateDto.getAreaRains();
            }
            // 出库流量
            List<Double> optimalLine_qreleases = singleDamOutput.getOptimalLine_Qrelease();
            // 期末水位   （common/optimal）
            List<Double> upLevelLimitArray = singleDamOutput.getUpLevelLimitArray();
            List<Double> optimalLine_level = singleDamOutput.getOptimalLine_Level();

            for (int i = 0; i < tms.size(); i++) {
                Double finalLevel = optimalLine_level.get(i);
                PreviewResult previewResult = PreviewResult.builder()
                        .id(IdUtils.getId())
                        .planId(plan.getId())
                        .tm(tms.get(i))   // 时间
                        .faceRainfall(Double.valueOf(df2.format(yureareaRains.get(i))))  //面雨量
                        .inQt(Double.valueOf(df.format(preQ.get(i))))   //入库流量
                        .outQt(Double.valueOf(df.format(optimalLine_qreleases.get(i))))   // 出库流量
                        .finalLevel(Double.valueOf(df1.format(finalLevel)))  //期末水位
                        .build();
                previewResults.add(previewResult);
            }
        } else {
            for (int i = 0; i < tms.size(); i++) {

                PreviewResult previewResult = PreviewResult.builder()
                        .id(IdUtils.getId())
                        .planId(plan.getId())
                        .tm(tms.get(i))   // 时间
                        .outQt(Double.valueOf(df.format(fqt.get(i))))   // 出库流量
                        .build();
                previewResults.add(previewResult);
            }
        }

        //previewResultService.saveBatch(previewResults);
        return previewResults;
    }

    /**
     * 风险评估数据入库
     *
     * @param plan
     */
    private PreviewRiskA insertPreviewRiskA(Plan plan) {
        Random random = new Random();
        Double[] dPopulace = new Double[]{1.21, 0.97, 1.34, 0.7};
        Double[] dFarmland = new Double[]{1.37, 1.53, 2.01, 1.1};
        double iArea = 30.0 + Math.random() * (50.0 - 30.0);
        Double dPopulacess = dPopulace[random.nextInt(3)];
        double affectDouble = dPopulacess * 10000 / 3;
        int affectInt = (int) affectDouble; // 显式类型转换
        double sDepth = 1 + Math.random() * (5 - 1);

        DecimalFormat df = new DecimalFormat("#.000");  //流量保留小数位数
        DecimalFormat df1 = new DecimalFormat("#.00");   //水位保留小数位数
        DecimalFormat df2 = new DecimalFormat("#.0");   //雨量保留小数位数

        PreviewRiskA previewRiskA = PreviewRiskA.builder()
                .id(IdUtils.getId())
                .planId(plan.getId())
                .affect(affectInt)   //影响户数
                .dPopulace(dPopulacess)   //受灾人口
                .iArea(Double.valueOf(df1.format(iArea)))  //最大淹没面积
                .sDepth(Double.valueOf(df1.format(sDepth)))  //最大淹没深度
                .dHouses(affectInt + 53)  // 受灾房屋
                .dFarmland(dFarmland[random.nextInt(3)])  //受灾农田
                .build();
        // previewRiskAService.insertPreviewRiskA(previewRiskA);
        return previewRiskA;
    }

    /**
     * 预演计算结果指标组装
     *
     * @param totalRainfall
     * @param tms
     * @param singleDamOutput
     */
    private PreviewPResult insertPreviewPResult(Double totalRainfall, List<Date> tms, SingleDamOutput singleDamOutput, String planId, String riskDanger, PlanFtParameterDto planFtParameterDto, List<Double> fqt) {
        //预演计算结果指标组装
        // 水库水位
        DecimalFormat df = new DecimalFormat("#.000");  //流量保留小数位数
        DecimalFormat dfy = new DecimalFormat("#.0");   //雨量保留小数位数
        DecimalFormat dfl = new DecimalFormat("#.00");//水位保留小数位数
        PreviewPResult previewPResult = null;
        if (singleDamOutput != null) {
            //调度建议
            String dAdvice = singleDamOutput.getSuggestion();
            //入库洪峰
            double floodPeak = singleDamOutput.getFloodPeak();
            // 入库洪峰时间
            String rkPeakTime = singleDamOutput.getRKPeakTime();
            // 入库洪量
            double floodVolume = singleDamOutput.getFloodVolume();
            // 期初水位
            double initialLevel = singleDamOutput.getInitialLevel();
            //最大泄流
            List<Double> optimalLine_qrelease = singleDamOutput.getOptimalLine_Qrelease();
            // 使用IntStream.range()生成一个索引流
            OptionalInt maxIndex = IntStream.range(0, optimalLine_qrelease.size())
                    .reduce((i, j) -> optimalLine_qrelease.get(i) >= optimalLine_qrelease.get(j) ? i : j);
            int index = maxIndex.getAsInt();
            double maxValue = optimalLine_qrelease.get(index);

            // 出库洪量
            double ckVolume = singleDamOutput.getCKVolume();
            // 期末水位
            double endLevel = singleDamOutput.getEndLevel();
            // 溢流及风险情况
            String maxLevelExceedStandard = singleDamOutput.getMaxLevelExceedStandard();


            //水库水位

            if (riskDanger.equals(RehearsalConstants.RISK_DANGER)) {
                maxLevelExceedStandard = RehearsalConstants.OVERFLOW_YES;
            } else {
                maxLevelExceedStandard = RehearsalConstants.OVERFLOW_NO;

            }

            previewPResult = PreviewPResult.builder()
                    .id(IdUtils.getId())
                    .planId(planId)
                    .dAdvice(dAdvice)  //调度建议

                    .inprek(Double.valueOf(df.format(floodPeak)))   //入库洪峰
                    .inprekTime(DateUtil.parse(rkPeakTime))  //入库洪峰时间
                    .invt(Double.valueOf(df.format(floodVolume * 10000)))   //入库洪量
                    .initialLevel(Double.valueOf(dfl.format(initialLevel)))   // 期初水位
                    .maxDrainage(Double.valueOf(df.format(maxValue)))    //最大泄流
                    .maxDTime(tms.get(index))   //最大泄流时间
                    .outqt(Double.valueOf(df.format(ckVolume * 10000)))   //出库洪量
                    .finalLevel(Double.valueOf(dfl.format(endLevel)))   // 期末水位
                    .effusionRisk(maxLevelExceedStandard)   //溢流及风险情况
                    .rLevel(planFtParameterDto.getQdWaterLevel())   //水库水位
                    .build();
            if (maxLevelExceedStandard.equals(RehearsalConstants.OVERFLOW_YES)) {
                previewPResult.setMaxSubmerge(15.0);   //最大淹没范围
                previewPResult.setMaxSTime(new Date());   //最大淹没时间
                previewPResult.setMaxSDepth(15.0);   //最大淹没深度
                previewPResult.setMaxSdTime(new Date());  //最大淹没深度时间
            }
        } else {
            OptionalInt maxIndex = IntStream.range(0, fqt.size())
                    .reduce((i, j) -> fqt.get(i) >= fqt.get(j) ? i : j);
            int index = maxIndex.getAsInt();
            double maxValue = fqt.get(index);
            previewPResult = PreviewPResult.builder()
                    .id(IdUtils.getId())
                    .planId(planId)
                    .maxDTime(tms.get(index))
                    .maxDrainage(maxValue)
                    .build();
        }
        if (totalRainfall != null) {
            previewPResult.setQRainfall(Double.valueOf(dfy.format(totalRainfall)));   //总降雨量
        }


        //previewPResultService.insertPreviewPResult(previewPResult);
        return previewPResult;
    }


    // 写入dat文件数据
    @Transactional
    public void initHz(Date startTime, List<Double> q_flood, List<Double> areaRains, List<String> t, String rscd) throws Exception {
        String content = "";
        String yucontent = "";

        List<Date> previous72WholeHours = getPrevious72WholeHours(startTime);

        QueryWrapper<RsvrRLaste> rsvrRLasteQueryWrapper = new QueryWrapper<>();
        rsvrRLasteQueryWrapper.eq("stcd", rscd).ge("tm", startTime).lt("tm", DateUtil.offsetDay(startTime, 3)).orderByAsc("tm");
        List<RsvrRLaste> list = rsvrRLasteService.list(rsvrRLasteQueryWrapper);

        if (list.size() != 72) {
            list = new ArrayList<RsvrRLaste>();
            // 创建一个LinkedList来保存时间序列
            List<Date> timeSeries = new LinkedList<>();

            // 使用Calendar来处理时间
            Calendar cal = Calendar.getInstance();
            cal.setTime(startTime); // 设置Calendar的时间为startTime

            // 生成72个时间点，每个时间点间隔1小时
            for (int i = 0; i < 72; i++) {
                timeSeries.add(cal.getTime()); // 将时间点加入时间序列
                cal.add(Calendar.HOUR_OF_DAY, 1); // 每次循环减去1小时
            }

            // 反转列表，确保时间序列从最早的开始
            //Collections.reverse(timeSeries);

            for (Date timeSery : timeSeries) {
                RsvrRLaste rsvrRLaste = new RsvrRLaste();
                rsvrRLaste.setTm(timeSery);
                rsvrRLaste.setInq(0.0);
                list.add(rsvrRLaste);
            }
        }

        //写流量上下游dat文件
        // 组装预热期数据
        for (RsvrRLaste rsvrR : list) {
            String format = new SimpleDateFormat("MM/dd/yyyy       HH:mm:ss").format(rsvrR.getTm());
            content += format + "    " + rsvrR.getInq() + "\n";
            yucontent += format + "    " + rsvrR.getInq() + "\n";
        }

        // 从数据获取数据并组装
        for (int i = 0; i < t.size(); i++) {
            String format = new SimpleDateFormat("MM/dd/yyyy       HH:mm:ss").format(DateUtil.parse(t.get(i)));
            content += format + "    " + q_flood.get(i) + "\n";
            yucontent += format + "    " + q_flood.get(i) + "\n";
        }

        //雨量数据dat数据组装
        /*Calendar calendar = Calendar.getInstance();
        calendar.setTime(startTime);
        calendar.add(Calendar.DAY_OF_MONTH, -3); // 往前推3天

        // 获取调整后的时间
        Date adjustedStartTime = calendar.getTime();
        HashMap<Object, Object> areaRainfall = DataUtil.getAreaRainfall(rscd, adjustedStartTime, startTime, 1);
        List<Double> yureareaRains = Convert.toList(Double.class, areaRainfall.get("areaRain"));
        List<String> yuretms = Convert.toList(String.class, areaRainfall.get("tms"));
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<Date> dates = new ArrayList<>();
        for (String yuretm : yuretms) {
            Date parse = simpleDateFormat.parse(yuretm);
            dates.add(parse);
        }
        for (int i = 0; i < yureareaRains.size(); i++) {
            String format = new SimpleDateFormat("MM/dd/yyyy       HH:mm:ss").format(dates.get(i));
            yucontent += format + "    " + yureareaRains.get(i) + "\n";
        }


        // 从数据获取数据并组装
        for (int i = 0; i < t.size(); i++) {
            String format = new SimpleDateFormat("MM/dd/yyyy       HH:mm:ss").format(DateUtil.parse(t.get(i)));
            yucontent += format + "    " + areaRains.get(i) + "\n";
        }*/

        // 文件输出路径
        String outputPath = System.getProperty("user.dir") + "/siyu-model/src/main/resources/swwm/djd_outflow.dat";
        String outputyuPath = System.getProperty("user.dir") + "/siyu-model/src/main/resources/swwm/djdh_outflow.dat";
        // 清空 流量.dat 文件
        try (FileWriter fw = new FileWriter(outputPath, false)) {
            fw.write("");
            fw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //清空下游dat
        try (FileWriter fw = new FileWriter(outputyuPath, false)) {
            fw.write("");
            fw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 将内容写入 流量.dat 文件
        try (FileWriter fw = new FileWriter(outputPath, true);
             BufferedWriter bw = new BufferedWriter(fw)) {
            bw.write(content); // 写入内容
            bw.flush(); // 刷新缓冲区


        } catch (IOException e) {
            e.printStackTrace();
        }
        //写入下游dat
        try (FileWriter fw = new FileWriter(outputyuPath, true);
             BufferedWriter bw = new BufferedWriter(fw)) {
            bw.write(yucontent); // 写入内容
            bw.flush(); // 刷新缓冲区


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理时间,获取预热期72小时
     *
     * @param startTime
     * @return
     */
    public static List<Date> getPrevious72WholeHours(Date startTime) {
        List<Date> previousHours = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startTime);

        // 确保startTime是整小时
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        previousHours.add(calendar.getTime());

        // 向前推72小时，每次都确保是整小时
        for (int i = 1; i <= 72; i++) {
            calendar.add(Calendar.HOUR_OF_DAY, -1);
            // 确保时间点为整点
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            previousHours.add(calendar.getTime());
        }

        // 由于是正序添加的，无需反转列表
        return previousHours;
    }

    // 修改inp文件时间
    @Transactional
    public void updateXinglongInpTime(Date before72Hrs, Date endTime, String inp) {
        String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(before72Hrs).replace("-", " ").replace(":", " ");
        String[] strs = format.split(" ");
        String sDate = strs[1] + "/" + strs[2] + "/" + strs[0];
        String sTime = strs[3] + ":" + strs[4] + ":" + strs[5];
        // 结束时间
        String format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(endTime).replace("-", " ").replace(":", " ");
        String[] strs1 = format1.split(" ");
        String eDate = strs1[1] + "/" + strs1[2] + "/" + strs1[0];
        String eTime = strs1[3] + ":" + strs1[4] + ":" + strs1[5];
        // 文件输出路径
        String inpoutputPath = System.getProperty("user.dir") + "/siyu-model/src/main/resources/swwm/" + inp + ".inp";
        String tempFilePath = System.getProperty("user.dir") + "/siyu-model/src/main/resources/swwm/temp.inp";
        try (BufferedReader br = new BufferedReader(new FileReader(inpoutputPath)); BufferedWriter bw = new BufferedWriter(new FileWriter(tempFilePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                if (line.contains("START_DATE")) {
                    line = "START_DATE           " + sDate;
                }
                if (line.contains("START_TIME")) {
                    line = "START_TIME           " + sTime;
                }
                if (line.contains("REPORT_START_DATE")) {
                    line = "REPORT_START_DATE    " + eDate;
                }
                if (line.contains("REPORT_START_TIME")) {
                    line = "REPORT_START_TIME    " + sTime;
                }
                if (line.contains("END_DATE")) {
                    line = "END_DATE             " + eDate;
                }
                if (line.contains("END_TIME")) {
                    line = "END_TIME             " + eTime;
                }
                bw.write(line + "\n");
            }
            br.close();
            bw.close();
            // 用新文件替换旧文件
            File oldFile = new File(inpoutputPath);
            oldFile.delete();
            File newFile = new File(tempFilePath);
            String contentAfterLastSlash = inpoutputPath.substring(inpoutputPath.lastIndexOf("/") + 1);
            newFile.renameTo(new File(newFile.getParent(), contentAfterLastSlash));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 新安江计算
     *
     * @param planCalculateDto
     * @return
     * @throws Exception
     */
    public HashMap<String, Object> hisCalc(PlanCalculateDto planCalculateDto) throws Exception {
        List<Date> tms = planCalculateDto.getTms();
        Date startTime = tms.get(0);
        Date endTime = tms.get(tms.size() - 1);
        long differenceInMillis = endTime.getTime() - startTime.getTime();
        Integer step = 1;

        // 获取面雨量
        HashMap<Object, Object> areaRainfall = DataUtil.getAreaRainfall(planCalculateDto.getRscd(), startTime, endTime, step);
        List<Double> areaRain = planCalculateDto.getAreaRains();
        // 蒸发序列
        List<Double> erList = IntStream.range(0, areaRain.size()).mapToObj(i -> 0.0).collect(Collectors.toList());
        // 获取模型参数
        QueryWrapper<ModelParam> modelParamQueryWrapper = new QueryWrapper<>();
        modelParamQueryWrapper.eq("model_mark", "xaj");
        Map<String, Double> map = modelParamService.list(modelParamQueryWrapper).stream()
                .collect(Collectors.toMap(ModelParam::getParamNum, ModelParam::getParamDefault, (oldValue, newValue) -> oldValue, HashMap::new));
        // 面积查询
        QueryWrapper<WrpRsrBsin> wrpRsrBsinQueryWrapper = new QueryWrapper<>();
        wrpRsrBsinQueryWrapper.eq("rscd", planCalculateDto.getRscd());
        WrpRsrBsin wrpRsrBsin = wrpRsrBsinService.getOne(wrpRsrBsinQueryWrapper);

        QueryWrapper<WrpRsrHych> wrpRsrHychQueryWrapper = new QueryWrapper<>();
        wrpRsrHychQueryWrapper.select("cnctar").eq("rscd", wrpRsrBsin.getRscd());

        //查找水库流域面积
        WrpRsrHych wrpRsrHych = wrpRsrHychService.getOne(wrpRsrHychQueryWrapper);
        XajData xajData = new XajData(areaRain, erList, step, wrpRsrHych.getCnctar(), map);
        // 开始新安江模型计算
        Map<Object, Object> calc = XajModel.calc(xajData);
        // 获取模型计算结果
        List<Double> preQ = Convert.toList(Double.class, calc.get("preQ"));
        List<String> tmss = Convert.toList(String.class, areaRainfall.get("tms"));
        List<XajResult> xajResults = new ArrayList<>();
        // 数据结果处理
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("preQ", preQ);
        resultMap.put("tms", tmss);
        return resultMap;
    }

    /**
     * swmm数据结果处理
     *
     * @param calculate
     * @return
     */
    public ArrayList<SwwmResult> savePlan(Object calculate, List<String> tmss, PlanCalculateDto planCalculateDto) {

        // 定义输入和输出的日期时间格式
        DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

        // 将字符串列表转换为格式化后的字符串列表
        List<String> formattedTmss = tmss.stream()
                .map(s -> LocalDateTime.parse(s, inputFormatter).format(outputFormatter))
                .collect(Collectors.toList());

        JSONObject jsonObject = JSONUtil.parseObj(calculate);
        com.alibaba.fastjson.JSONObject jsonObject1 = com.alibaba.fastjson.JSONObject.parseObject(calculate.toString());

        JSONArray jsonArray = new JSONArray();
        for (String key : jsonObject1.keySet()) {
            com.alibaba.fastjson.JSONObject subObject = jsonObject1.getJSONObject(key);
            jsonArray.add(subObject);
        }
        // 保存方案数据
        ArrayList<SwwmResult> list = new ArrayList<>();

        for (int i = 0; i < formattedTmss.size(); i++) {
            String time = formattedTmss.get(i);
            int size = jsonArray.size();
           /* if (!planCalculateDto.getRscd().equals(RehearsalConstants.DJD_RSCD)) {
                size = size + 1;
            }*/
            for (int j = 0; j < size; j++) {
                Object liuliang = JSONUtil.parseObj(jsonArray.get(j)).getJSONObject("liuliang").get(time);
                Object shuiwei = JSONUtil.parseObj(jsonArray.get(j)).getJSONObject("shuiwei").get(time);
                SwwmResult swwmResult = new SwwmResult();
                swwmResult.setOutletFlow(Double.valueOf(liuliang.toString()));
                swwmResult.setTm(time);
                swwmResult.setWaterLevel(Double.valueOf(shuiwei.toString()));
                list.add(swwmResult);
            }
        }
        return list;
    }


    @Override
    public PptnRResultVo getRain(PlanDispatchDto planDispatchDto) throws Exception {


        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        PptnRResultVo pptnRResultVo = new PptnRResultVo();
        DecimalFormat df = new DecimalFormat("#.0");
        if (planDispatchDto.getId() == null) {
            QueryWrapper<PptnRLaste> pptnRLasteQueryWrapper = new QueryWrapper<>();
            pptnRLasteQueryWrapper.select("tm", "drp")
                    .ge("tm", planDispatchDto.getStartTime())
                    .le("tm", planDispatchDto.getEndTime())
                    .orderByDesc("tm");
            List<PptnRLaste> pptnRS = pptnRLasteService.list(pptnRLasteQueryWrapper);

            HashMap<Object, Object> areaRainfall = DataUtil.getAreaRainfall(planDispatchDto.getRscd(), planDispatchDto.getStartTime(), planDispatchDto.getEndTime(), 1);

            List<String> tms = Convert.toList(String.class, areaRainfall.get("tms"));

            List<Double> areaRains = Convert.toList(Double.class, areaRainfall.get("areaRain"));

            Double sumDrp = 0.0;
            Double tm = 0.0;
            ArrayList<PptnRVo> pptnRVos = new ArrayList<>();
            for (int i = 0; i < tms.size(); i++) {
                PptnRVo pptnRVo = new PptnRVo();
                pptnRVo.setTm(tms.get(i).toString());
                pptnRVo.setDrp(areaRains.get(i));
                pptnRVos.add(pptnRVo);
                sumDrp += areaRains.get(i);
                if (areaRains.get(i) > 0) {
                    tm += 1;
                }
            }
            pptnRResultVo.setTotalTm(tm);
            pptnRResultVo.setTotalRainfal(Double.valueOf(df.format(sumDrp)));
            pptnRResultVo.setPptnRs(pptnRVos);

        } else {
            QueryWrapper<PreviewNd> previewNdQueryWrapper = new QueryWrapper<>();
            previewNdQueryWrapper.select("tm", "drp")
                    .eq("plan_id", planDispatchDto.getId())
                    .orderByAsc("tm");
            List<PreviewNd> previewNds = previewNdService.list(previewNdQueryWrapper);

            Double sumDrp = 0.0;
            Double tm = 0.0;
            ArrayList<PptnRVo> pptnRVos = new ArrayList<>();
            for (int i = 0; i < previewNds.size(); i++) {
                PreviewNd previewNd = previewNds.get(i);
                PptnRVo pptnRVo = new PptnRVo();
                pptnRVo.setTm(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(previewNd.getTm()));
                pptnRVo.setDrp(previewNd.getDrp());
                pptnRVos.add(pptnRVo);
                sumDrp += previewNd.getDrp();
                if (previewNd.getDrp() > 0) {
                    tm += 1;
                }
            }
          /*  String startTimeStr = previewNds.get(0).getTm();
            String endTimeStr = previewNds.get(previewNds.size() - 1).getTm();
            // 解析字符串为LocalDateTime对象
            LocalDateTime startTime = LocalDateTime.parse(startTimeStr, formatter);
            LocalDateTime endTime = LocalDateTime.parse(endTimeStr, formatter);

            // 计算两个时间之间的持续时间
            Duration duration = Duration.between(startTime,endTime );

            // 将持续时间转换为总小时数，保留小数
            Double tm = duration.toMillis() / (1000.0 * 60 * 60); // 或使用duration.toMinutes() / 60.0*/
            pptnRResultVo.setTotalTm(tm);
            pptnRResultVo.setTotalRainfal(Double.valueOf(df.format(sumDrp)));
            pptnRResultVo.setPptnRs(pptnRVos);
        }

        return pptnRResultVo;
    }

    @Override
    public Object getDispatchParameter(String rscd) {
        QueryWrapper<ModelParam> modelParamQueryWrapper = new QueryWrapper<>();
        modelParamQueryWrapper.select("rscd", "param_initial", "param_num")
                .eq("rscd", rscd)
                .eq("model_mark", "dd");
        List<ModelParam> modelParams = modelParamService.list(modelParamQueryWrapper);
        HashMap<String, Double> modelParamMap = new HashMap<>();
        for (int i = 0; i < modelParams.size(); i++) {
            ModelParam modelParam = modelParams.get(i);
            Double paramInitial = modelParam.getParamInitial();
            String paramNum = modelParam.getParamNum();
            switch (paramNum) {
                case RehearsalConstants.FLOOD_LEVEL:
                    modelParamMap.put(paramNum, paramInitial);   //汛限水位
                    break;
                case RehearsalConstants.DESIGN_WTATER_LEVERL:
                    modelParamMap.put(paramNum, paramInitial);   //设计洪水位
                    break;
                case RehearsalConstants.XZ_QRELEASE:
                    modelParamMap.put(paramNum, paramInitial);  //限制下泄流量
                    break;
                case RehearsalConstants.FC_QRELEASE:
                    modelParamMap.put(paramNum, paramInitial);  //非常泄洪
                    break;
                case RehearsalConstants.QD_WATER_LEVEL:
                    modelParamMap.put(paramNum, paramInitial);  //水位下限/起调水位
                    break;
                default:
                    break;
            }

        }
        return modelParamMap;
    }

    /**
     * 方案保存
     *
     * @param planPreviewSaveDto
     */
    @Override
    @Transactional
    public String savePlanPreview(PlanPreviewSaveDto planPreviewSaveDto) {
        Plan plan = planPreviewSaveDto.getPlan();
        PreviewRiskA previewRiskA = planPreviewSaveDto.getPreviewRiskA();
        PreviewPResult previewPResult = planPreviewSaveDto.getPreviewPResult();
        PreviewSresult previewSresult = planPreviewSaveDto.getPreviewSresult();
        List<PreviewResult> previewResults = planPreviewSaveDto.getPreviewResults();
        List<PreviewAffectV> previewAffectVS = planPreviewSaveDto.getPreviewAffectVS();
        List<PreviewNd> previewNds = planPreviewSaveDto.getPreviewNds();

        plan.setCreateTime(new Date());  //创建时间
        Plan plan1 = planService.getById(plan.getId());
        if (plan1 != null) {
            return RehearsalConstants.PLAN_EXIST;
        }

        planService.insertPlan(plan);
        ArrayList<Date> tms = new ArrayList<>();
        for (PreviewResult previewResult : previewResults) {
            tms.add(previewResult.getTm());
        }
        //统计最大淹没面积,最大淹没深度
        QueryWrapper<Dimension> dimensionQueryWrapper = new QueryWrapper<>();
        dimensionQueryWrapper.select("river_area")
                .eq("rscd", plan.getRscd())
                .eq("count_type", count_type);
        Dimension dimension = dimensionService.getOne(dimensionQueryWrapper);

        if (previewPResult.getMaxSubmerge()!=null) {
            if (!count_type.equals("cpu")) {
                zipPath = dimension.getOutgeoPath();
            }

            // 渲染数据上传
            String geoJsonUrl = uploadedJsonFile(tms, plan, "geo");
            previewSresult.setGeojson(geoJsonUrl);
        }
        if (previewSresult != null) {
            previewSresultService.insertPreviewSresult(previewSresult);
        }
        if (previewResults!=null){
            previewResultService.saveBatch(previewResults);
        }
        if (previewRiskA!=null){
            previewRiskAService.insertPreviewRiskA(previewRiskA);
        }
        if (previewPResult!=null){
            previewPResultService.save(previewPResult);
        }
        if (previewAffectVS != null) {
            previewAffectVService.saveBatch(previewAffectVS);
        }
        try {
            previewNdService.saveBatch(previewNds);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
        }
        return null;
    }

    /**
     * 统计最大淹没面积,最大淹没深度
     *
     * @param riverArea
     * @param previewRiskA
     * @param previewSresult
     * @param previewPResult
     */
    private ArrayList<PreviewAffectV> depthAndArea(Double riverArea, PreviewRiskA previewRiskA, PreviewSresult previewSresult, PreviewPResult previewPResult, String rscd, Plan plan) {
        Path directory = Paths.get(zipPath);
        ArrayList<PreviewAffectV> previewAffectVS = new ArrayList<>();

        try (Stream<Path> paths = Files.walk(directory)) {
            paths.filter(Files::isRegularFile)
                    .filter(p -> p.getFileName().toString().contains("max_wDepth"))
                    .forEach(p -> {
                        try {
                            String content = new String(Files.readAllBytes(p));
                            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(content, com.alibaba.fastjson.JSONObject.class);
                            com.alibaba.fastjson.JSONArray jsonArray = com.alibaba.fastjson.JSONObject.parseObject(jsonObject.get("features").toString(), com.alibaba.fastjson.JSONArray.class);
                            int size = jsonArray.size();
                            double i = Math.abs(Math.round(((size * 900 - riverArea) / 1000000.0) * 10.0) / 10.0);//最大淹没面积  k㎡
                            Integer DN = 0;
                            Integer SMDN = Integer.MAX_VALUE;
                            for (Object o : jsonArray) {
                                com.alibaba.fastjson.JSONObject features = com.alibaba.fastjson.JSONObject.parseObject(o.toString(), com.alibaba.fastjson.JSONObject.class);
                                com.alibaba.fastjson.JSONObject properties = com.alibaba.fastjson.JSONObject.parseObject(features.get("properties").toString(), com.alibaba.fastjson.JSONObject.class);
                                Integer dn = com.alibaba.fastjson.JSONObject.parseObject(properties.get("DN").toString(), Integer.class);
                                if (dn > DN) {
                                    DN = dn;
                                }
                                // 如果找到的 dn 比当前 DN 小，则更新 DN
                                if (dn < SMDN) {
                                    SMDN = dn;
                                }
                            }
                            // 最大淹没深度
                            double v = DN / 100.0;
                            double depth = Math.round(v * 10.0) / 10.0;
                            previewRiskA.setIArea(i);
                            previewRiskA.setSDepth(depth);
                            // 最小淹没深度
                            double smv = SMDN / 100.0;
                            double smdepth = Math.round(smv * 10.0) / 10.0;
                            previewRiskA.setSmDepth(smdepth);

                            previewSresult.setMaxFa(i);

                            if (yanmob) {
                                previewPResult.setMaxSubmerge(i);
                                previewPResult.setMaxSDepth(depth);
                            }

                            String pointsFilePath = rscd + ".geojson";
                            statistics(pointsFilePath, previewRiskA, previewSresult, previewAffectVS, rscd, plan);

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 统计最大淹没深度的时间和最大淹没范围的时间
        final Optional<Path>[] largestFile = new Optional[]{null};
        final long[] maxFileSize = {0};

        try (Stream<Path> paths = Files.walk(directory)) {
            paths.filter(Files::isRegularFile)
                    .filter(p -> p.getFileName().toString().contains("-") && p.toString().endsWith(".geojson"))
                    .forEach(p -> {
                        try {
                            long fileSize = Files.size(p);
                            if (fileSize > maxFileSize[0]) {
                                maxFileSize[0] = fileSize;
                                largestFile[0] = Optional.of(p);
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });

            if (largestFile[0].isPresent()) {
                System.out.println("The largest GeoJSON file is: " + largestFile[0].get());
            } else {
                System.out.println("No GeoJSON files found with '-' in their names.");
            }
            Path path = Paths.get(largestFile[0].get().toString());
            String fileName = path.getFileName().toString();

            // 分割文件名，去除扩展名
            String[] parts = fileName.split("\\.(?=[^\\.]+$)");
            String baseName = parts[0];

            // 再次分割基础文件名，去除前缀
            String[] dateParts = baseName.split("_");
            String dateTimePart = dateParts[2] + " " + dateParts[3];
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm");
            Date parse = sdf.parse(dateTimePart);

            if (yanmob) {
                previewPResult.setMaxSTime(parse);
                previewPResult.setMaxSdTime(parse);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return previewAffectVS;
    }


    @Override
    @Transactional
    public AjaxResult saveSight(PlanSightDto planSightDto) {

        try {
            Plan plan = Plan.builder()
                    .id(IdUtils.getId())
                    .planName(planSightDto.getPlanName())
                    .createBy(planSightDto.getCreateBy())
                    .planDesc(planSightDto.getPlanDesc())
                    .preType(RehearsalConstants.COUNT_TYPE_SCENE)
                    .createTime(new Date())
                    .rscd(planSightDto.getRscd())
                    .build();

            planService.save(plan);

            List<Double> iqs = planSightDto.getIqs();
            List<Date> tms = planSightDto.getTms();

            // 生成正态分布降雨
            Double totalDrp = planSightDto.getTotalDrp();
            int size = iqs.size();
            LinkedList<Double> drps = shenchengtuofengjiangyu(totalDrp, size);

            ArrayList<PreviewNd> previewNds = new ArrayList<>();
            LinkedList<PlanSightVo> planSightVos = new LinkedList<>();
            for (int i = 0; i < iqs.size(); i++) {
                Double iq = iqs.get(i);
                Date tm = tms.get(i);
                Double drp = drps.get(i);
                PreviewNd previewNd = PreviewNd.builder()
                        .id(IdUtils.getId())
                        .planId(plan.getId())
                        .qtS(iq)
                        .tm(tm)
                        .drp(drp)
                        .build();
                previewNds.add(previewNd);

                PlanSightVo planSightVo = PlanSightVo.builder()
                        .id(previewNd.getId())
                        .drp(drp)
                        .tm(tm)
                        .build();
                planSightVos.add(planSightVo);
            }
            previewNdService.saveBatch(previewNds);
            return AjaxResult.success(planSightVos);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error(RehearsalConstants.PLAN_SAVE_NO);
        }
    }

    @Override
    public Object getFalse(String id) {
        QueryWrapper<PptnRSence> pptnRSenceQueryWrapper = new QueryWrapper<>();
        pptnRSenceQueryWrapper.select("tm", "drp")
                .eq("sence_id", id);
        List<PptnRSence> pptnRSences = pptnRSenceService.list(pptnRSenceQueryWrapper);


        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        DecimalFormat df = new DecimalFormat("#.0");
        PptnRResultVo pptnRResultVo = new PptnRResultVo();


        Double sumDrp = 0.0;
        Double sumTm = 0.0;
        for (PptnRSence pptnRSence : pptnRSences) {
            Double drp = pptnRSence.getDrp();
            Date tm = pptnRSence.getTm();
            if (drp > 0) {
                sumDrp += drp;
                sumTm += 1;
            }

        }
        pptnRResultVo.setPptnRs(pptnRSences);
        pptnRResultVo.setTotalTm(sumTm);
        pptnRResultVo.setTotalRainfal(Double.valueOf(df.format(sumDrp)));
        return pptnRResultVo;
    }

    @Override
    public AjaxResult dbreak(String rscd, String preType) {
        List<PreviewNd> previewNds = null;
        try {
            QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
            planQueryWrapper.eq("rscd", rscd)
                    .eq("pre_type", preType);
            Plan plan = planService.getOne(planQueryWrapper);

            QueryWrapper<PreviewNd> previewNdQueryWrapper = new QueryWrapper<>();
            previewNdQueryWrapper.eq("plan_id", plan.getId())
                    .orderByAsc("tm");
            previewNds = previewNdService.list(previewNdQueryWrapper);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("查询失败!");
        }
        return AjaxResult.success(previewNds);
    }

    @Override
    public AjaxResult getfbase(String rscd) {
        try {
            QueryWrapper<PreviewPFbase> previewPFbaseQueryWrapper = new QueryWrapper<>();
            previewPFbaseQueryWrapper.eq("rscd", rscd);
            List<PreviewPFbase> list = previewPFbaseService.list(previewPFbaseQueryWrapper);
            return AjaxResult.success(list);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("查询失败!");
        }
    }

    @Override
    @Transactional
    public AjaxResult upfbase(List<PreviewPFbase> previewPFbases) {
        try {
            for (PreviewPFbase previewPFbase : previewPFbases) {
                if (previewPFbase.getId() == null) {
                    previewPFbase.setId(IdUtils.getId());
                    previewPFbaseService.save(previewPFbase);
                }else {
                    previewPFbaseService.updatePreviewPFbase(previewPFbase);
                }
            }
            //previewPFbaseService.updateBatchById(previewPFbases);
            return AjaxResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("修改失败!");
        }
    }

    @Override
    public HashMap<String, Object> calculation(PreviewForTDto previewForTDto) {
        // 处理调度规则
        HashMap<String, Boolean> gateSettings = previewForTDto.getGateSettings();

//        HashMap<String, LinkedList<Double>> inq = new HashMap<>();
//        for (String crossSection : crossSections) {
//            HashMap<String, Object> map = topology.get(crossSection);
//            LinkedList<Double> liuliang = com.alibaba.fastjson.JSONObject.parseObject(map.get("liuliang").toString(), LinkedList.class);
//            inq.put(crossSection, liuliang);
//        }

        // 判断流量序列和时间序列是否为空
        if (BeanUtil.isEmpty(previewForTDto.getTms()) || BeanUtil.isEmpty(previewForTDto.getInq())) {
            return AjaxResult.error("时间序列或者流量序列不能为空");
        }
        // 判断流量序列和时间序列长度是否相等
        if (previewForTDto.getTms().size() != previewForTDto.getInq().get("ssh-1").size()) {
            return AjaxResult.error("时间序列或者流量序列长度不一致");
        }

        // 生成方案id
        Plan plan = new Plan();
        String id = IdUtil.getSnowflake().nextIdStr();
        plan.setId(id);
        plan.setComputeType("0");
        plan.setRscd(previewForTDto.getRscd());
        planService.insertPlan(plan);

        // 异步调用二维计算逻辑
        new Thread(() -> {
            try {
                String address = pengurl;
                // 构造 JSON 请求体
                JSONObject requestBody = new JSONObject();
                requestBody.set("id", id);
                requestBody.set("basinPath", "/resources/pengModel/liuyu/"+previewForTDto.getRscd()+"/");
                requestBody.set("outputGeojsonPath", "/resources/pengModel/liuyu/"+previewForTDto.getRscd()+"/geojson");
                requestBody.set("startTime", previewForTDto.getTms().get(0));
                requestBody.set("endTime", previewForTDto.getTms().get(previewForTDto.getTms().size() - 1));
                requestBody.set("flows", previewForTDto.getInq());
                requestBody.set("gateSettings", previewForTDto.getGateSettings());
                requestBody.set("hpengurl", hpengurl);
                // 发起 POST 请求
                HttpRequest.post(address)
                        .header("Content-Type", "application/json")
                        .body(requestBody.toString())
                        .execute();
            } catch (Exception e) {
                // 处理异常，可以记录日志
                e.printStackTrace();
            }
        }).start();
        HashMap<String, Object> map = new HashMap<>();
        //map.put("od", topology);
        map.put("plan", plan);
        map.put("tm", previewForTDto.getTms());

        return map;
    }

    /**
     * 生成正态分布降雨
     *
     * @param totalDrp
     * @param size
     * @return
     */
    private LinkedList<Double> shenchengtuofengjiangyu(double totalDrp, int size) {
        double[] sequence = new double[size];
        int midIndex = size / 2;
        // 分配总降雨量到中间元素
        double drpPerElement = totalDrp / size;
        sequence[midIndex] = drpPerElement;
        // 从中心点向两边分配降雨量，使用不同的递减率
        for (int i = 1; i <= midIndex; i++) {
            if (midIndex + i < size) {
                sequence[midIndex + i] = sequence[midIndex + i - 1] * Math.random();
            }
            if (midIndex - i >= 0) {
                sequence[midIndex - i] = sequence[midIndex - i + 1] * Math.random();
            }
        }
        // 调整序列总和
        double currentTotal = 0;
        for (int i = 0; i < size; i++) {
            currentTotal += sequence[i];
        }
        double ratio = totalDrp / currentTotal;
        for (int i = 0; i < size; i++) {
            sequence[i] *= ratio;
        }
        // 四舍五入到两位小数
        for (int i = 0; i < size; i++) {
            sequence[i] = Math.round(sequence[i] * 10.0) / 10.0;
        }
        // 转换为LinkedList并返回
        LinkedList<Double> doubles = new LinkedList<>();
        for (int i = 0; i < sequence.length; i++) {
            doubles.add(sequence[i]);
            System.out.println(sequence[i]);
        }
        return doubles;
    }

    public void main(String[] args) {
        shenchengtuofengjiangyu(1156.63, 25);
    }

    public void statistics(String pointsFilePath, PreviewRiskA previewRiskA, PreviewSresult previewSresult, ArrayList<PreviewAffectV> previewAffectVS, String rscd, Plan plan) throws Exception {
        // 设置 Python 脚本路径
        String pythonScriptPath = "./siyu-model/src/main/resources/statistics/statistics.py";

        // 设置 GeoJSON 文件路径
        pointsFilePath = "./siyu-model/src/main/resources/statistics/" + pointsFilePath;
        String polygonsFilePath = "./modeldata/itf_max_wDepth.geojson";

        // 检查并安装 Python 依赖项
        if (RehearsalConstants.PORP3) {
            try {
                checkAndInstallPythonDependencies();
            } catch (Exception e) {
                System.err.println("Failed to install Python dependencies.");
                e.printStackTrace();
                return;
            }
        }

        // 创建 ProcessBuilder 并设置命令
        ProcessBuilder processBuilder = null;
        if (RehearsalConstants.PORP3) {
            processBuilder = new ProcessBuilder("python", pythonScriptPath, pointsFilePath, polygonsFilePath);
        } else {
            processBuilder = new ProcessBuilder("python3", pythonScriptPath, pointsFilePath, polygonsFilePath);
        }
        Process process = processBuilder.start();

        // 读取标准输出
        BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "utf-8"));
        BufferedReader stderrReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "utf-8"));

        // 读取并打印标准输出
        String line;
        int count = 0;
        double totalArea = 0;
        double totalFarmArea = 0;
        List<String> namesOfPoints = new ArrayList<>();

        while ((line = stdoutReader.readLine()) != null) {
            //System.out.println(line);  // 打印 Python 脚本的输出

            // 使用正则表达式匹配输出
            Pattern pCount = Pattern.compile("num: (\\d+)");
            Matcher mCount = pCount.matcher(line);
            if (mCount.find()) {
                count = Integer.parseInt(mCount.group(1));
            }

            Pattern pArea = Pattern.compile("zmj: (\\d+\\.\\d+)");
            Matcher mArea = pArea.matcher(line);
            if (mArea.find()) {
                totalArea = Double.parseDouble(mArea.group(1));
            }

            Pattern pFarmArea = Pattern.compile("fzarea: (\\d+\\.\\d+)");
            Matcher mFarmArea = pFarmArea.matcher(line);
            if (mFarmArea.find()) {
                totalFarmArea = Double.parseDouble(mFarmArea.group(1));
            }

            Pattern pNames = Pattern.compile("names: \\[(.*)\\]");
            Matcher mNames = pNames.matcher(line);
            if (mNames.find()) {
                String namesString = mNames.group(1);
                String[] namesArray = namesString.split(", ");
                for (String name : namesArray) {
                    namesOfPoints.add(name.replaceAll("\"", ""));
                }
            }
        }

        // 读取并打印标准错误输出
        while ((line = stderrReader.readLine()) != null) {
            System.err.println(line);
        }

        // 等待进程结束
        int exitCode = process.waitFor();
        System.out.println("Process exited with code: " + exitCode);

        // 关闭资源
        stdoutReader.close();
        stderrReader.close();

        //影响户数
        Integer affect = 0;
        //影响人口
        Integer dPopulace = 0;
        //影响房屋
        Integer dHouses = 0;
        // 影响农田
        Double dFarmland = 0.0;
        // 影响耕地
        Double iPlh = 0.0;
        for (String name : namesOfPoints) {
            QueryWrapper<PreviewPFbase> previewPFbaseQueryWrapper = new QueryWrapper<>();
            name = name.substring(1, name.length() - 1);
            previewPFbaseQueryWrapper.eq("rscd", rscd)
                    .eq("v_name", name);
            PreviewPFbase previewPFbase = previewPFbaseService.getOne(previewPFbaseQueryWrapper);

            //淹没村庄信息统计
            PreviewAffectV previewAffectV = PreviewAffectV.builder()
                    .id(IdUtils.getId())
                    .planId(plan.getId())
                    .inp(previewPFbase.getIPpl())
                    .villageName(previewPFbase.getVName())
                    .lOfficial(previewPFbase.getLOfficial())
                    .district(previewPFbase.getDistrict())
                    .build();
            previewAffectVS.add(previewAffectV);

            affect += previewPFbase.getIDoor();
            dPopulace += previewPFbase.getIPpl();
            dHouses += previewPFbase.getIH();
            dFarmland += previewPFbase.getIPh();
            iPlh += previewPFbase.getIPlh();
        }

        // 创建 DecimalFormat 对象，并设置格式为两位小数
        DecimalFormat df = new DecimalFormat("#.####");

        //预演结果风险评估对象
        previewRiskA.setAffect(affect);
        Double aDouble = Double.valueOf(df.format(dPopulace / 10000.0));
        previewRiskA.setDPopulace(Math.abs(aDouble));
        previewRiskA.setDHouses(dHouses);
        Double Farmland = Double.valueOf(df.format(dFarmland / 10000.0));
        previewRiskA.setDFarmland(Farmland);

        previewSresult.setFv(count);
        previewSresult.setIPopulace(previewRiskA.getDPopulace());
        previewSresult.setAal(iPlh);
        previewSresult.setAh(dHouses);
        //previewRiskA
        //previewSresult
        //previewAffectVS
        // 输出结果
  /*      System.out.println("点的数量: " + count);
        System.out.println("总面积: " + totalArea);
        System.out.println("总农场面积: " + totalFarmArea);
        System.out.println("点的名称: " + namesOfPoints);*/
    }

    public static void main() throws Exception {
        // 设置 Python 脚本路径
        String pythonScriptPath = "./siyu-model/src/main/resources/statistics/statistics.py";

        // 设置 GeoJSON 文件路径
        String pointsFilePath = "./siyu-model/src/main/resources/statistics/43060030012-A411.geojson";
        String polygonsFilePath = "./modeldata/itf_max_wDepth.geojson";

        // 检查并安装 Python 依赖项
        try {
            checkAndInstallPythonDependencies();
        } catch (Exception e) {
            System.err.println("Failed to install Python dependencies.");
            e.printStackTrace();
            return;
        }

        // 创建 ProcessBuilder 并设置命令
        ProcessBuilder processBuilder = new ProcessBuilder("python", pythonScriptPath, pointsFilePath, polygonsFilePath);
        Process process = processBuilder.start();

        // 读取标准输出
        BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
        BufferedReader stderrReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8));

        // 读取并打印标准输出
        String line;
        int count = 0;
        double totalArea = 0.0;
        double totalFarmArea = 0.0;
        List<String> namesOfPoints = new ArrayList<>();


        while ((line = stdoutReader.readLine()) != null) {
            System.out.println(line);  // 打印 Python 脚本的输出
            // 使用正则表达式匹配输出
            Pattern pCount = Pattern.compile("num: (\\d+)");
            Matcher mCount = pCount.matcher(line);
            if (mCount.find()) {
                count = Integer.parseInt(mCount.group(1));
            }

            Pattern pArea = Pattern.compile("zmj: (\\d+\\.\\d+)");
            Matcher mArea = pArea.matcher(line);
            if (mArea.find()) {
                totalArea = Double.parseDouble(mArea.group(1));
            }

            Pattern pFarmArea = Pattern.compile("fzarea: (\\d+\\.\\d+)");
            Matcher mFarmArea = pFarmArea.matcher(line);
            if (mFarmArea.find()) {
                totalFarmArea = Double.parseDouble(mFarmArea.group(1));
            }

            Pattern pNames = Pattern.compile("names: \\[(.*)\\]");
            Matcher mNames = pNames.matcher(line);
            if (mNames.find()) {
                String namesString = mNames.group(1);
                String[] namesArray = namesString.split(", ");
                for (String name : namesArray) {
                    namesOfPoints.add(name.replaceAll("\"", ""));
                }
            }
        }

        // 读取并打印标准错误输出
        while ((line = stderrReader.readLine()) != null) {
            System.err.println(line);
        }

        // 等待进程结束
        int exitCode = process.waitFor();
        System.out.println("Process exited with code: " + exitCode);

        // 关闭资源
        stdoutReader.close();
        stderrReader.close();

        // 输出结果
        System.out.println("点的数量: " + count);
        System.out.println("总面积: " + totalArea);
        System.out.println("总农场面积: " + totalFarmArea);
        System.out.println("点的名称: " + namesOfPoints);
    }


    private static void checkAndInstallPythonDependencies() throws Exception {
        // 需要检查的模块列表
        List<String> modulesToCheck = new ArrayList<>();
        modulesToCheck.add("geojson");
        modulesToCheck.add("Shapely");

        for (String moduleName : modulesToCheck) {
            // 尝试导入模块以检查是否已安装
            ProcessBuilder pb = null;
            if (RehearsalConstants.PORP3) {
                pb = new ProcessBuilder("python", "-c", "import " + moduleName);
            } else {
                pb = new ProcessBuilder("python3", "-c", "import " + moduleName);
            }
            Process p = pb.start();
            int exitCode = p.waitFor();

            if (exitCode != 0) {
                // 模块未安装，尝试安装
                installPythonDependency(moduleName);
            }
        }
    }

    private static void installPythonDependency(String moduleName) throws Exception {
        // 安装模块
        ProcessBuilder pb = new ProcessBuilder("pip", "install", moduleName);
        Process p = pb.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        reader.close();
        int exitCode = p.waitFor();
        if (exitCode != 0) {
            throw new RuntimeException("Failed to install the Python module: " + moduleName);
        }
    }
}
